package top.goldenyear.porpoise.framework.web.core.service;

import cn.hutool.v7.core.bean.BeanUtil;
import cn.hutool.v7.core.collection.CollUtil;
import cn.hutool.v7.core.reflect.FieldUtil;
import com.easy.query.api.proxy.client.EasyEntityQuery;
import com.easy.query.api.proxy.entity.delete.ExpressionDeletable;
import com.easy.query.api.proxy.entity.insert.EntityInsertable;
import com.easy.query.api.proxy.entity.select.EntityQueryable;
import com.easy.query.api.proxy.entity.update.EntityUpdatable;
import com.easy.query.api.proxy.entity.update.ExpressionUpdatable;
import com.easy.query.core.basic.api.delete.ClientExpressionDeletable;
import com.easy.query.core.basic.api.insert.ClientInsertable;
import com.easy.query.core.basic.api.select.ClientQueryable;
import com.easy.query.core.basic.api.update.ClientEntityUpdatable;
import com.easy.query.core.enums.SQLExecuteStrategyEnum;
import com.easy.query.core.expression.builder.core.AnyValueFilter;
import com.easy.query.core.expression.builder.core.NotNullOrEmptyValueFilter;
import com.easy.query.core.expression.builder.core.ValueFilter;
import com.easy.query.core.expression.lambda.SQLActionExpression1;
import com.easy.query.core.expression.parser.core.base.WherePredicate;
import com.easy.query.core.proxy.ProxyEntity;
import com.easy.query.core.proxy.ProxyEntityAvailable;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
import top.goldenyear.porpoise.framework.web.core.model.PageResult;
import top.goldenyear.porpoise.framework.web.core.model.query.QPage;
import top.goldenyear.porpoise.framework.web.core.model.query.QSort;

/**
 * 返回值是列表/分页时，支持空条件被忽略，方便条件设置。 返回值是单个查询时，空条件也是查询条件，避免多查。
 *
 * @author airhead
 */
public abstract class BaseService<
    T extends ProxyEntityAvailable<T, TProxy>, TProxy extends ProxyEntity<TProxy, T>> {

  private final Class<T> tClass;

  private final Class<TProxy> tProxyClass;

  public BaseService(Class<T> tClass, Class<TProxy> tProxyClass) {
    this.tClass = tClass;
    this.tProxyClass = tProxyClass;
  }

  public Boolean existAttr(String attr) {
    // 有缓存系统
    Map<String, Field> fieldMap = FieldUtil.getFieldMap(getTClass());
    return fieldMap.containsKey(attr);
  }

  public Boolean notExistAttr(String attr) {
    return !existAttr(attr);
  }

  /**
   * 过滤条件为空时，不参与查询
   *
   * @return
   */
  public EntityQueryable<TProxy, T> nonEmptyEntityQueryable() {
    return entityQueryable(NotNullOrEmptyValueFilter.DEFAULT);
  }

  public EntityQueryable<TProxy, T> entityQueryable() {
    return easyEntityQuery().queryable(tClass).filterConfigure(AnyValueFilter.DEFAULT);
  }

  public EntityQueryable<TProxy, T> entityQueryable(ValueFilter valueFilter) {
    return easyEntityQuery().queryable(tClass).filterConfigure(valueFilter);
  }

  public EntityQueryable<TProxy, T> entityQueryable(String sql, Collection<Object> params) {
    return entityQueryable(sql, params, AnyValueFilter.DEFAULT);
  }

  /**
   * 过滤条件为空时，不参与查询
   *
   * @return
   */
  public EntityQueryable<TProxy, T> nonEmptyEntityQueryable(String sql, Collection<Object> params) {
    return entityQueryable(sql, params, NotNullOrEmptyValueFilter.DEFAULT);
  }

  public EntityQueryable<TProxy, T> entityQueryable(
      String sql, Collection<Object> params, ValueFilter valueFilter) {
    return easyEntityQuery().queryable(sql, tClass, params).filterConfigure(valueFilter);
  }

  public ExpressionDeletable<TProxy, T> entityDeletable() {
    return easyEntityQuery().deletable(tClass).allowDeleteStatement(true);
  }

  public ExpressionUpdatable<TProxy, T> entityUpdatable() {
    return easyEntityQuery().updatable(tClass);
  }

  public EntityUpdatable<TProxy, T> entityUpdatable(T model) {
    return easyEntityQuery().updatable(model);
  }

  public EntityInsertable<TProxy, T> entityInsertable(T model) {
    return easyEntityQuery().insertable(model);
  }

  public EntityInsertable<TProxy, T> entityInsertable(List<T> models) {
    return easyEntityQuery().insertable(models);
  }

  public ClientQueryable<T> queryable() {
    return queryable(AnyValueFilter.DEFAULT);
  }

  /**
   * 过滤条件为空时，不参与查询
   *
   * @return
   */
  public ClientQueryable<T> nonEmptyQueryable() {
    return queryable(NotNullOrEmptyValueFilter.DEFAULT);
  }

  public ClientQueryable<T> queryable(ValueFilter valueFilter) {
    return easyEntityQuery().getEasyQueryClient().queryable(tClass).filterConfigure(valueFilter);
  }

  public ClientQueryable<T> queryable(String sql, Collection<Object> params) {
    return queryable(sql, params, AnyValueFilter.DEFAULT);
  }

  /**
   * 过滤条件为空时，不参与查询
   *
   * @return
   */
  public ClientQueryable<T> nonEmptyQueryable(String sql, Collection<Object> params) {
    return queryable(sql, params, NotNullOrEmptyValueFilter.DEFAULT);
  }

  public ClientQueryable<T> queryable(
      String sql, Collection<Object> params, ValueFilter valueFilter) {
    return easyEntityQuery()
        .getEasyQueryClient()
        .queryable(sql, tClass, params)
        .filterConfigure(valueFilter);
  }

  public ClientExpressionDeletable<T> deletable() {
    return easyEntityQuery().getEasyQueryClient().deletable(tClass).allowDeleteStatement(true);
  }

  public ClientInsertable<T> insertable(T model) {
    return easyEntityQuery().getEasyQueryClient().insertable(model);
  }

  public ClientInsertable<T> insertable(List<T> models) {
    return easyEntityQuery().getEasyQueryClient().insertable(models);
  }

  public ClientEntityUpdatable<T> updatable(T model) {
    return easyEntityQuery().getEasyQueryClient().updatable(model);
  }

  public ClientEntityUpdatable<T> updatable(List<T> models) {
    return easyEntityQuery().getEasyQueryClient().updatable(models);
  }

  public Boolean exists(String attr, Object value, String idAttr, Serializable id) {
    return queryable()
            .where(
                t -> {
                  t.eq(attr, value);
                  t.ne(idAttr, id);
                })
            .firstOrNull()
        != null;
  }

  /**
   * 统计总记录数
   *
   * @return 记录数
   */
  public long count() {
    return queryable().count();
  }

  /**
   * 通过 Model 统计满足条件的记录数
   *
   * @param model Model 对象
   * @return 记录数
   */
  public long count(T model) {
    return this.count(model != null ? BeanUtil.beanToMap(model) : null);
  }

  /**
   * 通过 Map 统计满足条件的记录数
   *
   * @param map Map 参数表
   * @return 记录数
   */
  public long count(Map<String, ?> map) {
    return queryable()
        .where(
            t -> {
              for (Map.Entry<String, ?> entry : map.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                t.eq(key, value);
              }
            })
        .count();
  }

  public long count(SQLActionExpression1<TProxy> whereExp) {
    return entityQueryable().where(whereExp).count();
  }

  /**
   * 通过 Model 删除满足条件的记录
   *
   * @param model Model 对象
   * @return 记录数
   */
  public long delete(T model) {
    if (model == null) {
      return 0L;
    }

    return this.delete(BeanUtil.beanToMap(model));
  }

  /**
   * 通过 Map 删除满足条件的记录
   *
   * @param map Map 参数表
   * @return 记录数
   */
  public long delete(Map<String, ?> map) {
    if (map == null || map.isEmpty()) {
      return 0L;
    }

    return deletable()
        .where(
            new SQLActionExpression1<WherePredicate<T>>() {
              @Override
              public void apply(WherePredicate<T> t) {
                map.forEach(t::eq);
              }
            })
        .executeRows();
  }

  /**
   * 通过 Map 删除满足条件的记录
   *
   * @param whereExp 条件
   * @return 记录数
   */
  public long delete(SQLActionExpression1<TProxy> whereExp) {
    return entityDeletable().where(whereExp).executeRows();
  }

  /**
   * 根据 ID 删除记录
   *
   * @param id 记录的 ID
   * @return 是否成功
   */
  public boolean deleteById(Serializable id) {
    return deletable().whereById(id).executeRows() > 0L;
  }

  /**
   * 根据多个 ID 批量删除记录
   *
   * @param ids ID 列表
   * @return 是否成功删除任意记录
   */
  public boolean deleteByIds(Collection<? extends Serializable> ids) {
    return deletable().whereByIds(ids).executeRows() > 0L;
  }

  /**
   * 查询所有记录
   *
   * <p>数据量大时请谨慎使用
   *
   * @return Model 对象列表
   */
  public List<T> list() {
    return queryable().toList();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param model Model 对象
   * @return Model 对象列表
   */
  public List<T> list(T model) {
    return this.list(model != null ? BeanUtil.beanToMap(model) : null);
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param whereExp Model 对象
   * @return Model 对象列表
   */
  public List<T> list(SQLActionExpression1<TProxy> whereExp) {
    return nonEmptyEntityQueryable().where(whereExp).toList();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param whereExp Model 对象
   * @return Model 对象列表
   */
  public List<T> list(SQLActionExpression1<TProxy> whereExp, long rows) {
    return nonEmptyEntityQueryable().where(whereExp).limit(rows).toList();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param whereExp Model 对象
   * @return Model 对象列表
   */
  public List<T> listX(SQLActionExpression1<WherePredicate<T>> whereExp) {
    return queryable().where(whereExp).toList();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param whereExp Model 对象
   * @return Model 对象列表
   */
  public List<T> listX(SQLActionExpression1<WherePredicate<T>> whereExp, long rows) {
    return queryable().where(whereExp).limit(rows).toList();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param model Model 对象
   * @param sort 排序列名
   * @return Model 对象列表
   */
  public List<T> list(T model, List<QSort> sort) {
    return this.list(model != null ? BeanUtil.beanToMap(model) : null, sort);
  }

  /**
   * 通过 Map 查找满足条件的记录列表
   *
   * @param map Map 参数表
   * @return Model 对象列表
   */
  public List<T> list(Map<String, ?> map) {
    return this.list(map, null);
  }

  /**
   * 通过 Map 查找满足条件的记录列表,并按指定条件排序
   *
   * @param map Map 参数表
   * @param sort 排序列名
   * @return Model 对象列表
   */
  public List<T> list(Map<String, ?> map, List<QSort> sort) {
    ClientQueryable<T> queryable = nonEmptyQueryable();
    fillQuery(queryable, map);
    fillSort(queryable, sort);

    return queryable.toList();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @return Model 对象列表
   */
  public <V> List<V> listAs(Class<V> vClass) {
    return nonEmptyEntityQueryable().select(vClass).toList();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @return Model 对象列表
   */
  public <V> List<V> listAs(T model, Class<V> vClass) {
    return this.listAs(model != null ? BeanUtil.beanToMap(model) : null, vClass);
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @return Model 对象列表
   */
  public <V> List<V> listAs(Map<String, ?> data, Class<V> vClass) {
    ClientQueryable<T> queryable = nonEmptyQueryable();
    fillQuery(queryable, data);

    return nonEmptyEntityQueryable().select(vClass).toList();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param modelProxy Model 对象
   * @return Model 对象列表
   */
  public <V> List<V> listAs(SQLActionExpression1<TProxy> modelProxy, Class<V> vClass) {
    return nonEmptyEntityQueryable().where(modelProxy).select(vClass).toList();
  }

  /**
   * 通过 ids 查找记录
   *
   * @param idList 记录的 ID
   * @return Model 对象
   */
  public List<T> listByIds(Collection<? extends Serializable> idList) {
    return queryable().whereByIds(idList).toList();
  }

  /**
   * 通过 ID 查找记录
   *
   * @param id 记录的 ID
   * @return Model 对象
   */
  public T getById(Serializable id) {
    return queryable().whereById(id).firstOrNull();
  }

  public T getByAttr(String attr, Object value) {
    return queryable().where(t -> t.eq(attr, value)).firstOrNull();
  }

  /**
   * 通过 Model 查找满足条件的单条记录
   *
   * @param model Model 对象
   * @return Model 对象
   */
  public T get(T model) {
    if (model == null) {
      return null;
    }

    return this.get(BeanUtil.beanToMap(model));
  }

  /**
   * 通过 Model 查找满足条件的单条记录
   *
   * @param model Model 对象
   * @param orderColumn 排序列名
   * @param orderDirection 排序方向："asc" 正序，"desc" 倒序。如果为Null则默认为"asc"
   * @return Model 对象
   */
  public T get(T model, String orderColumn, String orderDirection) {
    if (model == null) {
      return null;
    }

    QSort querySort = new QSort();
    querySort.setSortName(orderColumn);
    querySort.setSortMethod(orderDirection);
    return this.get(BeanUtil.beanToMap(model), Collections.singletonList(querySort));
  }

  /**
   * 根据 Map 查找单条记录
   *
   * @param map Map 参数表
   * @return Model 对象
   */
  public T get(Map<String, ?> map) {
    return this.get(map, null);
  }

  /**
   * 根据 Map 查找单条记录,并按指定条件排序
   *
   * @param map Map 参数表
   * @param sort 排序列名
   * @return Model 对象
   */
  public T get(Map<String, ?> map, List<QSort> sort) {
    ClientQueryable<T> queryable = queryable();
    fillQuery(queryable, map);
    fillSort(queryable, sort);

    return queryable.firstOrNull();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param modelProxy Model 对象
   * @return Model 对象列表
   */
  public T get(SQLActionExpression1<TProxy> modelProxy) {
    return entityQueryable().where(modelProxy).firstOrNull();
  }

  /**
   * 通过 Model 查找满足条件的记录列表
   *
   * @param modelProxy Model 对象
   * @return Model 对象列表
   */
  public <V> V getAs(SQLActionExpression1<TProxy> modelProxy, Class<V> vClass) {
    return entityQueryable().where(modelProxy).select(vClass).firstOrNull();
  }

  /**
   * 分页返回记录
   *
   * @param qPage 起始值为1的页号
   * @return Model 分页对象
   */
  public PageResult<T> paginate(QPage qPage) {
    return new PageResult<>(
        nonEmptyQueryable().toPageResult(qPage.getPageNumber(), qPage.getPageSize()),
        qPage.getPageNumber(),
        qPage.getPageSize());
  }

  /**
   * 分页返回记录
   *
   * @param pageNumber 起始值为1的页号
   * @param pageSize 默认值为10的页大小
   * @return Model 分页对象
   */
  public PageResult<T> paginate(int pageNumber, int pageSize) {
    return new PageResult<>(
        nonEmptyQueryable().toPageResult(pageNumber, pageSize), pageNumber, pageSize);
  }

  /**
   * 通过 Model 查找满足条件的分页记录
   *
   * @param qPage 起始值为1的页号
   * @param model Model 对象
   * @return Model 分页对象
   */
  public PageResult<T> paginate(QPage qPage, T model) {
    return paginate(
        qPage.getPageNumber(),
        qPage.getPageSize(),
        model != null ? BeanUtil.beanToMap(model) : null,
        null);
  }

  /**
   * 通过 Model 查找满足条件的分页记录
   *
   * @param pageNumber 起始值为1的页号
   * @param pageSize 默认值为10的页大小
   * @param model Model 对象
   * @return Model 分页对象
   */
  public PageResult<T> paginate(int pageNumber, int pageSize, T model) {
    return paginate(pageNumber, pageSize, model != null ? BeanUtil.beanToMap(model) : null, null);
  }

  /**
   * 通过 Model 查找满足条件的分页记录
   *
   * @param pageNumber 起始值为1的页号
   * @param pageSize 默认值为10的页大小
   * @param model Model 对象
   * @param sort 排序列名
   * @return Model 分页对象
   */
  public PageResult<T> paginate(int pageNumber, int pageSize, T model, List<QSort> sort) {
    return paginate(pageNumber, pageSize, model != null ? BeanUtil.beanToMap(model) : null, sort);
  }

  /**
   * 通过 Map 查找满足条件的分页记录
   *
   * @param pageNumber 起始值为1的页号
   * @param pageSize 默认值为10的页大小
   * @param map Map 参数表
   * @return Model 分页对象
   */
  public PageResult<T> paginate(int pageNumber, int pageSize, Map<String, ?> map) {
    return paginate(pageNumber, pageSize, map, null);
  }

  /**
   * 通过 Map 查找分页记录,并按指定条件排序
   *
   * @param pageNumber 起始值为1的页号
   * @param pageSize 默认值为10的页大小
   * @param map Map 参数表
   * @param sort 排序列名
   * @return Model 分页对象
   */
  public PageResult<T> paginate(
      int pageNumber, int pageSize, Map<String, ?> map, List<QSort> sort) {
    ClientQueryable<T> queryable = nonEmptyQueryable();
    fillQuery(queryable, map);
    fillSort(queryable, sort);
    return new PageResult<>(queryable.toPageResult(pageNumber, pageSize), pageNumber, pageSize);
  }

  public PageResult<T> paginate(QPage qPage, SQLActionExpression1<TProxy> modelProxy) {
    return new PageResult<>(
        nonEmptyEntityQueryable()
            .where(modelProxy)
            .toPageResult(qPage.getPageNumber(), qPage.getPageSize()),
        qPage.getPageNumber(),
        qPage.getPageSize());
  }

  public <V> PageResult<V> paginateAs(QPage qPage, Class<V> vClass) {
    return new PageResult<>(
        nonEmptyEntityQueryable()
            .select(vClass)
            .toPageResult(qPage.getPageNumber(), qPage.getPageSize()),
        qPage.getPageNumber(),
        qPage.getPageSize());
  }

  public <V> PageResult<V> paginateAs(
      QPage qPage, SQLActionExpression1<TProxy> modelProxy, Class<V> vClass) {
    return new PageResult<>(
        nonEmptyEntityQueryable()
            .where(modelProxy)
            .select(vClass)
            .toPageResult(qPage.getPageNumber(), qPage.getPageSize()),
        qPage.getPageNumber(),
        qPage.getPageSize());
  }

  /**
   * 保存 Model 记录
   *
   * @param model 对象
   * @return 是否成功
   */
  public boolean save(T model) {
    return save(model, true);
  }

  /**
   * 保存 Model 记录
   *
   * @param model 对象
   * @return 是否成功
   */
  public boolean save(T model, boolean fillAutoIncrement) {
    if (model == null) {
      return false;
    }

    return insertable(model).executeRows(fillAutoIncrement) > 0L;
  }

  /**
   * 批量保存 Model 记录
   *
   * @param list Model 对象列表
   * @return 成功数
   */
  public boolean batchSave(List<T> list) {
    return insertable(list).batch().executeRows() > 0L;
  }

  /**
   * 更新 Model 记录
   *
   * @param model 对象
   * @return 是否成功
   */
  public boolean updateById(T model) {
    return updateById(model, false);
  }

  /**
   * 更新 Model 记录
   *
   * @param model 对象
   * @return 是否成功
   */
  public boolean updateById(T model, boolean allColumns) {
    if (allColumns) {
      return updateById(model, SQLExecuteStrategyEnum.ALL_COLUMNS);
    }

    return updateById(model, SQLExecuteStrategyEnum.ONLY_NOT_NULL_COLUMNS);
  }

  /**
   * 更新 Model 记录
   *
   * @param model 对象
   * @return 是否成功
   */
  public boolean updateById(T model, SQLExecuteStrategyEnum strategy) {
    if (model == null) {
      return false;
    }

    return entityUpdatable(model).setSQLStrategy(strategy).executeRows() > 0;
  }

  public boolean update(
      SQLActionExpression1<TProxy> updateExp, SQLActionExpression1<TProxy> whereExp) {
    return entityUpdatable().where(whereExp).setColumns(updateExp).executeRows() > 0;
  }

  /**
   * 批量更新 Model 记录
   *
   * @param list 对象列表
   * @return 更新数
   */
  public void batchUpdate(List<T> list) {
    if (list == null || list.isEmpty()) {
      return;
    }

    updatable(list).batch().executeRows();
  }

  protected Class<T> getTClass() {
    return tClass;
  }

  protected Class<TProxy> getTProxyClass() {
    return tProxyClass;
  }

  /**
   * 获取实际的检索的 EasyEntityQuery
   *
   * @return EasyEntityQuery
   */
  protected abstract EasyEntityQuery easyEntityQuery();

  /**
   * 获取查询条件
   *
   * @param map 条件
   * @return
   */
  protected void fillQuery(ClientQueryable<T> queryable, Map<String, ?> map) {
    if (CollUtil.isEmpty(map)) {
      return;
    }

    queryable.where(t -> map.forEach(t::eq));
  }

  protected void fillSort(ClientQueryable<T> queryable, List<QSort> sortList) {
    if (CollUtil.isEmpty(sortList)) {
      return;
    }

    sortList.forEach(
        s -> {
          queryable.orderBy(
              tColumnOrderSelector -> tColumnOrderSelector.column(s.getSortName()),
              "desc".equals(s.getSortMethod()));
        });
  }
}
